#pragma once

#include <iostream>
#include <string>
#include <poll.h>
#include "Log.hpp"
#include "Socket.hpp"
#include <memory>

using namespace Net_Work;
using namespace std;

const static int gdefaultport = 8888;
const static int gbacklog = 8;
const int gnum = 1024;

class PollServer
{
private:
    void HandlerEvent()
    {
        for (int i = 0; i < _num; i++)
        {
            if (_rfds[i].fd == -1)
                continue;
            // 合法的sockfd
            // 读事件分两类，一类是新连接到来，一类是新数据到来
            int fd = _rfds[i].fd;
            short revents = _rfds[i].revents;
            if (revents & POLLIN)
            {
                // 读事件就绪
                if (fd == _listensock->GetSockFd()) // 说明是连接事件到来
                {
                    lg.LogMessage(Info, "get a new link\n");
                    // 获取连接
                    string clientip;
                    uint16_t clientport;
                    int sock = _listensock->AcceptConnection(&clientip, &clientport);
                    if (sock == -1)
                    {
                        lg.LogMessage(Error, "accept error\n");
                        continue;
                    }
                    lg.LogMessage(Info, "get a new client info is# %s:%d, fd: %d\n", clientip.c_str(), clientport, sock);
                    // 新连接fd到来的时候，不能直接读取，而是要把新的fd，想办法交给poll托管,只需要添加到_rfds即可
                    int pos = 0;
                    for (; pos < _num; ++pos)
                    {
                        if (_rfds[pos].fd == -1)
                        {
                            _rfds[pos].fd = sock;
                            _rfds[pos].events = POLLIN;
                            lg.LogMessage(Info, "get a new link, fd is : %d\n", sock);
                            break;
                        }
                    }
                    if (pos == _num)
                    {
                        // 扩容 或 关闭
                        close(sock);
                        lg.LogMessage(Warning, "server is full...!\n");
                    }
                }
                else
                {
                    // 普通的读事件就绪
                    // 读数据是有问题的
                    // 因为到这里的文件描述符已经就绪了，所以读取绝对不会阻塞
                    char buffer[1024];
                    ssize_t n = recv(fd, buffer, sizeof(buffer - 1), 0);
                    if (n > 0)
                    {
                        buffer[n] = 0;
                        lg.LogMessage(Info, "client say# %s\n", buffer);
                        string message = "hello world, ";
                        message += buffer;
                        send(fd, message.c_str(), message.size(), 0);
                    }
                    else
                    {
                        // 出错
                        lg.LogMessage(Info, "client quit, maybe close or error, close fd: %d\n", fd);
                        close(fd);
                        // 取消poll的关心
                        _rfds[i].fd = -1;
                        _rfds[i].events = 0;
                        _rfds[i].revents = 0;
                    }
                }
            }
        }
    }

public:
    PollServer(int port = gdefaultport)
        : _port(port), _listensock(new TcpSocket()), _isrunning(false), _num(gnum)
    {
    }
    ~PollServer()
    {
        delete[] _rfds;
    }
    void InitServer()
    {
        _listensock->BuildListenSocketMethod(_port, gbacklog);
        _rfds = new struct pollfd[_num];
        for(int i = 0; i < _num; ++i)
        {
            _rfds[i].fd = -1;
            _rfds[i].events = 0;
            _rfds[i].revents = 0;
        }
        //最开始只有一个文件描述符,listensock
        _rfds[0].fd = _listensock->GetSockFd();
        _rfds[0].events |= POLLIN;// 新连接到来，属于POLLIN事件
    }
    void Loop()
    {
        _isrunning = true;
        while (_isrunning)
        {
            // 定义时间
            int timeout = 1000; // 1s
            PrintDebug();
            int n = poll(_rfds, _num, timeout);
            switch (n)
            {
            case 0:
                lg.LogMessage(Info, "poll timeout...\n");
                break;
            case -1:
                lg.LogMessage(Error, "poll error!!!\n");
                break;
            default:
                // 正常就绪的fd
                lg.LogMessage(Error, "poll success, begin event handler\n");
                HandlerEvent();
                break;
            }
        }
        _isrunning = false;
    }
    void Stop()
    {
        _isrunning = false;
    }

    void PrintDebug()
    {
        cout << "current poll fd list is : ";
        for (int i = 0; i < _num; i++)
        {
            if (_rfds[i].fd == -1)
                continue;
            else
            {
                cout << _rfds[i].fd << " ";
            }
        }
        cout << endl;
    }

private:
    std::unique_ptr<Socket> _listensock;
    int _port;
    bool _isrunning;

    struct pollfd *_rfds;
    int _num;
};